class Solution:
    def longestStrChain(self, words: list) -> int:
        def func(counter, word, memo):
            if word in memo:
                return memo[word]
            if len(word) == 1:
                return 1
            res = 1
            nextWords = counter[len(word) -
                                1] if len(word) - 1 in counter else set()
            for i in range(len(word)):
                nextWord = word[:i] + word[i + 1:]
                if nextWord in nextWords:
                    res = max(func(counter, nextWord, memo) + 1, res)
            memo[word] = res
            return res

        counter = {}
        for word in words:
            if len(word) not in counter:
                counter[len(word)] = set()
            counter[len(word)].add(word)

        ans = 0
        memo = {}
        for length in sorted(counter.keys(), reverse=True):
            for word in counter[length]:
                ans = max(ans, func(counter, word, memo))

        return ans
